#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
缓存管理器
实现基于Redis的缓存功能，支持chain_type+key的哈希缓存
"""

import redis
import json
import hashlib
from typing import Any, Optional, Union
from config import Config
from utils.logger import get_logger

logger = get_logger(__name__)

class CacheManager:
    """Redis缓存管理器"""
    
    def __init__(self, config: Config = None):
        """初始化缓存管理器
        
        Args:
            config: 配置对象，如果为None则使用默认配置
        """
        self.config = config or Config()
        self._redis_client = None
        self._connect()
    
    def _connect(self):
        """连接Redis服务器"""
        try:
            self._redis_client = redis.Redis(
                host=self.config.REDIS_HOST,
                port=self.config.REDIS_PORT,
                password=self.config.REDIS_PASSWORD,
                db=self.config.REDIS_DB,
                decode_responses=self.config.REDIS_DECODE_RESPONSES,
                socket_connect_timeout=5,
                socket_timeout=5,
                retry_on_timeout=True
            )
            # 测试连接
            self._redis_client.ping()
            logger.info(f"Successfully connected to Redis at {self.config.REDIS_HOST}:{self.config.REDIS_PORT}")
        except Exception as e:
            logger.error(f"Failed to connect to Redis: {e}")
            self._redis_client = None
    
    def _generate_cache_key(self, chain_type: str, key: str) -> str:
        """生成缓存键
        
        Args:
            chain_type: 区块链类型
            key: 原始键
            
        Returns:
            生成的缓存键
        """
        # 使用chain_type+key生成哈希
        raw_key = f"{chain_type}+{key}"
        hash_key = hashlib.md5(raw_key.encode('utf-8')).hexdigest()
        return f"{self.config.CACHE_KEY_PREFIX}:{hash_key}"
    
    def get(self, chain_type: str, key: str) -> Optional[Any]:
        """从缓存中获取数据
        
        Args:
            chain_type: 区块链类型
            key: 缓存键
            
        Returns:
            缓存的数据，如果不存在则返回None
        """
        if not self._redis_client:
            logger.warning("Redis client not available, cache get failed")
            return None
        
        try:
            cache_key = self._generate_cache_key(chain_type, key)
            cached_data = self._redis_client.get(cache_key)
            
            if cached_data:
                logger.debug(f"Cache hit for key: {chain_type}+{key}")
                return json.loads(cached_data)
            else:
                logger.debug(f"Cache miss for key: {chain_type}+{key}")
                return None
                
        except Exception as e:
            logger.error(f"Error getting cache for key {chain_type}+{key}: {e}")
            return None
    
    def set(self, chain_type: str, key: str, value: Any, timeout: Optional[int] = None) -> bool:
        """设置缓存数据
        
        Args:
            chain_type: 区块链类型
            key: 缓存键
            value: 要缓存的数据
            timeout: 过期时间（秒），如果为None则使用默认配置
            
        Returns:
            是否设置成功
        """
        if not self._redis_client:
            logger.warning("Redis client not available, cache set failed")
            return False
        
        try:
            cache_key = self._generate_cache_key(chain_type, key)
            cache_timeout = timeout or self.config.CACHE_DEFAULT_TIMEOUT
            
            # 序列化数据
            serialized_value = json.dumps(value, ensure_ascii=False)
            
            # 设置缓存
            result = self._redis_client.setex(
                cache_key, 
                cache_timeout, 
                serialized_value
            )
            
            if result:
                logger.debug(f"Cache set for key: {chain_type}+{key}, timeout: {cache_timeout}s")
                return True
            else:
                logger.warning(f"Failed to set cache for key: {chain_type}+{key}")
                return False
                
        except Exception as e:
            logger.error(f"Error setting cache for key {chain_type}+{key}: {e}")
            return False
    
    def delete(self, chain_type: str, key: str) -> bool:
        """删除缓存数据
        
        Args:
            chain_type: 区块链类型
            key: 缓存键
            
        Returns:
            是否删除成功
        """
        if not self._redis_client:
            logger.warning("Redis client not available, cache delete failed")
            return False
        
        try:
            cache_key = self._generate_cache_key(chain_type, key)
            result = self._redis_client.delete(cache_key)
            
            if result:
                logger.debug(f"Cache deleted for key: {chain_type}+{key}")
                return True
            else:
                logger.debug(f"Cache key not found for deletion: {chain_type}+{key}")
                return False
                
        except Exception as e:
            logger.error(f"Error deleting cache for key {chain_type}+{key}: {e}")
            return False
    
    def exists(self, chain_type: str, key: str) -> bool:
        """检查缓存键是否存在
        
        Args:
            chain_type: 区块链类型
            key: 缓存键
            
        Returns:
            缓存键是否存在
        """
        if not self._redis_client:
            return False
        
        try:
            cache_key = self._generate_cache_key(chain_type, key)
            return bool(self._redis_client.exists(cache_key))
        except Exception as e:
            logger.error(f"Error checking cache existence for key {chain_type}+{key}: {e}")
            return False
    
    def get_ttl(self, chain_type: str, key: str) -> int:
        """获取缓存键的剩余生存时间
        
        Args:
            chain_type: 区块链类型
            key: 缓存键
            
        Returns:
            剩余生存时间（秒），-1表示永不过期，-2表示键不存在
        """
        if not self._redis_client:
            return -2
        
        try:
            cache_key = self._generate_cache_key(chain_type, key)
            return self._redis_client.ttl(cache_key)
        except Exception as e:
            logger.error(f"Error getting TTL for key {chain_type}+{key}: {e}")
            return -2
    
    def clear_pattern(self, pattern: str) -> int:
        """根据模式清除缓存
        
        Args:
            pattern: 匹配模式
            
        Returns:
            删除的键数量
        """
        if not self._redis_client:
            return 0
        
        try:
            keys = self._redis_client.keys(f"{self.config.CACHE_KEY_PREFIX}:{pattern}")
            if keys:
                deleted_count = self._redis_client.delete(*keys)
                logger.info(f"Cleared {deleted_count} cache keys matching pattern: {pattern}")
                return deleted_count
            return 0
        except Exception as e:
            logger.error(f"Error clearing cache with pattern {pattern}: {e}")
            return 0
    
    def get_cache_info(self) -> dict:
        """获取缓存信息
        
        Returns:
            缓存服务器信息
        """
        if not self._redis_client:
            return {"status": "disconnected"}
        
        try:
            info = self._redis_client.info()
            return {
                "status": "connected",
                "redis_version": info.get("redis_version"),
                "used_memory": info.get("used_memory_human"),
                "connected_clients": info.get("connected_clients"),
                "total_commands_processed": info.get("total_commands_processed"),
                "keyspace_hits": info.get("keyspace_hits"),
                "keyspace_misses": info.get("keyspace_misses")
            }
        except Exception as e:
            logger.error(f"Error getting cache info: {e}")
            return {"status": "error", "error": str(e)}
    
    def close(self):
        """关闭Redis连接"""
        if self._redis_client:
            try:
                self._redis_client.close()
                logger.info("Redis connection closed")
            except Exception as e:
                logger.error(f"Error closing Redis connection: {e}")
            finally:
                self._redis_client = None

# 全局缓存管理器实例
cache_manager = CacheManager()

# 便捷函数
def get_cache(chain_type: str, key: str) -> Optional[Any]:
    """获取缓存数据的便捷函数"""
    return cache_manager.get(chain_type, key)

def set_cache(chain_type: str, key: str, value: Any, timeout: Optional[int] = None) -> bool:
    """设置缓存数据的便捷函数"""
    return cache_manager.set(chain_type, key, value, timeout)

def delete_cache(chain_type: str, key: str) -> bool:
    """删除缓存数据的便捷函数"""
    return cache_manager.delete(chain_type, key)

def cache_exists(chain_type: str, key: str) -> bool:
    """检查缓存是否存在的便捷函数"""
    return cache_manager.exists(chain_type, key)